/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "imageknife_test.h"
#include "imageknife.h"
namespace ImageKnifeTest {
using namespace ImageKnifePro;

/**
 * 示例一，使用系统接口在pixelmap原图上处理
 * 对图片进行逆时针旋转90度
 */
class MyTransformationRotate : public Transformation {
    // 在这里实现自己的图片处理逻辑
    bool Transform(std::shared_ptr<ImageKnifeTask> task) override
    {
        if (task == nullptr) {
            return false;
        }
        if (task->product.imageData == nullptr) {
            task->EchoError("imageData is empty");
            return false;
        }

        // 这里只处理第一帧作为示例，不考虑动图多帧的情况
        OH_PixelmapNative *pixelmap = task->product.imageData->GetPixelmap();
        if (pixelmap == nullptr) {
            task->EchoError("pixelmap is nullptr");
            return false;
        }

        // 对pixelmap进行处理, 使用系统接口进行旋转做演示
        const float angle = -90;
        OH_PixelmapNative_Rotate(pixelmap, angle);
        return true;
    }

    // 描述图形变换信息，用于内存缓存key生成
    std::string GetTransformInfo() override
    {
        return "MyTransformation Rotate";
    }
};

/**
 * 示例二，使用系统接口在创建新pixelmap，在原始buffer上处理
 * 将Red通道变为原来的一半
 */
class MyTransformationHalfRed : public Transformation {
    // 在这里实现自己的图片处理逻辑
    bool Transform(std::shared_ptr<ImageKnifeTask> task) override
    {
        if (task == nullptr) {
            return false;
        }
        if (task->product.imageData == nullptr) {
            task->EchoError("imageData is empty");
            return false;
        }

        // 这里只处理第一帧作为示例，不考虑动图多帧的情况
        OH_PixelmapNative *pixelmap = task->product.imageData->GetPixelmap();
        if (pixelmap == nullptr) {
            task->EchoError("pixelmap is nullptr");
            return false;
        }

        // 对pixelmap进行处理
        auto pixelmapOut = DoHalfRed(pixelmap);
        if (pixelmapOut == nullptr) {
            task->EchoError("Do Opacity Failed");
            return false;
        }

        // 新创建的pixelmap需要覆盖原来的
        task->product.imageData = std::make_shared<ImageData>(pixelmapOut);
        return true;
    }

    // 描述图形变换信息，用于内存缓存key生成
    std::string GetTransformInfo() override
    {
        return "MyTransformation HalfRed";
    }

    Image_Size GetIamgeSize(OH_PixelmapNative *pixelmap)
    {
        Image_Size imageSize = {0, 0};
        OH_Pixelmap_ImageInfo *imageInfo = nullptr;
        if (OH_PixelmapImageInfo_Create(&imageInfo)) {
            return imageSize;
        }

        if (OH_PixelmapNative_GetImageInfo(pixelmap, imageInfo)) {
            OH_PixelmapImageInfo_Release(imageInfo);
            return imageSize;
        }

        int32_t format = PIXEL_FORMAT_UNKNOWN;
        OH_PixelmapImageInfo_GetPixelFormat(imageInfo, &format);
        if (format != PIXEL_FORMAT_RGBA_8888) {
            OH_PixelmapImageInfo_Release(imageInfo);
            return imageSize;
        }

        OH_PixelmapImageInfo_GetWidth(imageInfo, &imageSize.width);
        OH_PixelmapImageInfo_GetHeight(imageInfo, &imageSize.height);
        OH_PixelmapImageInfo_Release(imageInfo);
        return imageSize;
    }

    OH_PixelmapNative *CreatePixelmap(Image_Size imageSize, uint8_t *buffer, size_t bufferLength)
    {
        OH_Pixelmap_InitializationOptions *options = nullptr;
        OH_PixelmapInitializationOptions_Create(&options);

        OH_PixelmapInitializationOptions_SetWidth(options, imageSize.width);
        OH_PixelmapInitializationOptions_SetHeight(options, imageSize.height);
        OH_PixelmapInitializationOptions_SetPixelFormat(options, PIXEL_FORMAT_RGBA_8888);
        OH_PixelmapInitializationOptions_SetSrcPixelFormat(options, PIXEL_FORMAT_RGBA_8888);

        OH_PixelmapNative *pixelmapOut = nullptr;
        OH_PixelmapNative_CreatePixelmap(buffer, bufferLength, options, &pixelmapOut);
        OH_PixelmapInitializationOptions_Release(options);

        // 释放buffer
        free(buffer);
        return pixelmapOut;
    }
    
    // 返回新的pixelmap
    OH_PixelmapNative *DoHalfRed(OH_PixelmapNative *pixelmap)
    {
        auto imageSize = GetIamgeSize(pixelmap);
        if (imageSize.width == 0 || imageSize.height == 0) {
            return nullptr;
        }

        const size_t channel = 4;
        size_t length = imageSize.width * imageSize.height * channel;
        uint8_t *buffer = (uint8_t *)malloc(length);
        if (OH_PixelmapNative_ReadPixels(pixelmap, buffer, &length)) {
            free(buffer);
            return nullptr;
        }

        // 这里简单起见，使用CPU遍历buffer将red降为当前的一半做演示
        // 可以使用opengl进行GPU加速
        const size_t half = 2;
        for (int h = 0; h < imageSize.height; h++) {
            for (int w = 0; w < imageSize.width; w++) {
                int redIndex = (h * imageSize.width + w) * channel;
                buffer[redIndex] /= half;
            }
        }

        return CreatePixelmap(imageSize, buffer, length);
    }
};

/**
 * 示例三，带参自由裁剪变换, 需要配合TransformationConstructor使用
 * 使用系统接口对pixelmap进行裁剪
 */
class MyTransformationCrop : public Transformation {
public:
    // 图形变换对象接收参数
    MyTransformationCrop(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
        : x_(x), y_(y), width_(width), height_(height)
    {
        transformInfo_ = "MyTransformation Crop:" + std::to_string(x_) + "," + std::to_string(y_) + "," +
                         std::to_string(width_) + "," + std::to_string(height_);
    }

    // 在这里实现自己的图片处理逻辑
    bool Transform(std::shared_ptr<ImageKnifeTask> task) override
    {
        if (task == nullptr) {
            return false;
        }
        if (task->product.imageData == nullptr) {
            task->EchoError("imageData is empty");
            return false;
        }

        // 这里只处理第一帧作为示例，不考虑动图多帧的情况
        OH_PixelmapNative *pixelmap = task->product.imageData->GetPixelmap();
        if (pixelmap == nullptr) {
            task->EchoError("pixelmap is nullptr");
            return false;
        }

        Image_Region region = {.x = x_, .y = y_, .width = width_, .height = height_};
        OH_PixelmapNative_Crop(pixelmap, &region);
        return true;
    }

    // 描述图形变换信息，用于内存缓存key生成
    std::string GetTransformInfo() override
    {
        return transformInfo_;
    }
private:
    std::string transformInfo_;

    uint32_t x_ = 0;
    uint32_t y_ = 0;
    uint32_t width_ = 0;
    uint32_t height_ = 0;
};

/**
 * 示例三 使用TransformationConstructor来构造
 */
class TransformationCropConstructor : public TransformationConstructor {
public:
    std::shared_ptr<Transformation> CreateTransformation(std::shared_ptr<TransformationOption> option) override
    {
        if (option == nullptr) {
            return nullptr;
        }

        const size_t four = 4;
        // 参数错误返回空对象，即实际上不裁剪处理
        if (option->f32.size() < four) {
            return nullptr;
        }

        const size_t widthIndex = 2;
        const size_t heightIndex = 3;

        return std::make_shared<MyTransformationCrop>(option->f32[0], option->f32[1],
                                                      option->f32[widthIndex], option->f32[heightIndex]);
    }
};

/**
 * 注册自定义的图形变换对象，以供ArkTs层使用
 * ArkTs层使用注册的名称字符串来匹配对应的图形变换对象和构造者
 */
void RegisterCustomTransformation()
{
    auto transformRotate = std::make_shared<MyTransformationRotate>();
    auto transformHalfRed = std::make_shared<MyTransformationHalfRed>();
    ImageKnife::GetInstance().RegisterTransformation("CustomTransformRotate", transformRotate);
    ImageKnife::GetInstance().RegisterTransformation("CustomTransformHalfRed", transformHalfRed);

    // 注册TransformationConstructor
    auto transformConstructor = std::make_shared<TransformationCropConstructor>();
    ImageKnife::GetInstance().RegisterTransformationConstructor("CustomTransformCrop", transformConstructor);
}

}

